package gameLogic;
import static entity.GameBoard.*;

import java.awt.Color;
import java.util.Arrays;

import boundary.Adapter;
import desktop_codebehind.Car;
import entity.DiceCup;
import entity.GameBoard;
import entity.Ownable;
import entity.Spiller;


public class Spil {

	private GameBoard gameboard;
	private DiceCup dicecup;
	private Spiller[] s;
	private desktop_fields.Field[] guiFields;
	private boolean game;

	/**
	 * Opretter et spil med tilhørende elementer bestående af et spillebræt indeholdende felter, et raflebæger indeholdende terninger.
	 */
	public Spil()
	{
		gameboard = new GameBoard();
		gameboard.feltSetup();
		gameboard.shuffleArray();
		gameboard.createGuiFields();
		this.guiFields = gameboard.getGuiFields();
		gameboard.createGUI(guiFields);
		dicecup = new DiceCup();
		game = true;
	}

	/**
	 * Opret spillere og sæt dem på spillepladen.
	 */
	public void createPlayers(){
		int choice = Adapter.jOption();

		s = new Spiller[choice]; //skal muligvis flyttes tilbage til konstruktøren
		int[][] color = new int[][] {{255,0,0},{0,255,0},{0,0,255},{255,255,0},{0,255,255},{255,0,255}};

		for ( int i=0; i<choice; i++)
		{ //<-- oprettelse af spillere
			s[i] = new Spiller();
			s[i].setName(Adapter.showTypeName()); // Adapter fortæller GUI'en at den skal vise: "indtast spillernavn"
			if (s[i].getName()==null || s[i].getName().isEmpty()) // Hvis intet indtastes, får spillerne navne fra spiller1-6
			{
				int r = i+1;
				s[i].setName(Adapter.player()+r);				
			}

			// Opretter color-objekt til hver spiller (R,B,G)
			Color sColor = new Color(color[i][0],color[i][1],color[i][2]);

			Car car;
			int type = Adapter.chooseCar(); // Brugeren får lov at vælge hvilken type bil han ønsker
			switch (type){
			case 1: {
				car = new Car.Builder()
				.typeRacecar()
				.primaryColor(sColor)
				.build();
			}
			break;
			case 2: {
				car = new Car.Builder()
				.typeUfo()
				.primaryColor(sColor)
				.build();
			}
			break;
			case 3: {
				car = new Car.Builder()
				.typeTractor()
				.primaryColor(sColor)
				.build();
			}
			break;
			case 4: {
				car = new Car.Builder()
				.typeCar()
				.primaryColor(sColor)
				.build();
			}
			break;
			default: {
				car = new Car.Builder()
				.typeCar()
				.primaryColor(sColor)
				.build();
			}
			break;
			}

			Adapter.addPlayer(s[i].getName(), s[i].getKonto().getBalance(), car); // Tilføjer spilleren på spillepladen
			Adapter.setCar(1, s[i].getName()); // Placerer bilen på start feltet.
		}
	}

	/**
	 * Begynd spillet!
	 */
	public void launchGame()
	{
		while(game){
			int i = 1;
			for (i=0; i<s.length; i++){
				if (s[i].getKonto().getBalance() >= 0){
					Adapter.rollDice(s[i].getName()); // Beder spilleren trykke OK/Enter for at slå med terningerne
					dicecup.rollDice(); // Slår med terningerne
					Adapter.setDice(dicecup.getDice()[0], 0, 4, 3, dicecup.getDice()[1], 0, 6, 3); // Viser terningeslaget på interface
					Adapter.removeCar(s[i].getPosition(), s[i].getName());

					//sørger for at spillerens position starter forfra når enden af pladen nås
					if(s[i].getPosition()+dicecup.sum()>field.length){
						s[i].setPosition(dicecup.sum()-((field.length)-s[i].getPosition()));
					}
					else{
						s[i].setPosition(s[i].getPosition()+dicecup.sum());
					}

					Adapter.setCar(s[i].getPosition(), s[i].getName());
					guiFields[s[i].getPosition()-1].displayOnCenter(); // Viser feltets beskrivelse i midten af GUI'en når der landes på det.
					field[s[i].getPosition()-1].landOnField(s[i]);
					// Vi opdaterer GUI'en med samtlige spilleres balance hver gang der landes på et felt
					for (int n=0; n<s.length; n++){
						Adapter.setBalance(s[n].getName(), s[n].getKonto().getBalance());
					}
				}
			}
			s = playerUpd(s);
		}
		winner(); // Når game = false, skal der findes en vinder
	}

	/**
	 * Annoncerer en vinder (eller to i tilfælde af uafgjort).
	 */
	public void winner(){
		if(s.length>1){ // Hvis de er mere end én vinder så spillet skal ende uafgjort
			String name = s[0].getName();
			if(s.length>2){
			for (int i=1; i<s.length-1; i++){
				name += ", ";
				name += s[i].getName();
				}
			}
			name+=" og "+s[s.length-1].getName();
			Adapter.draw(name);
		}
		else if(s.length==1){ // Der er fundet en vinder
			Adapter.winner(s[0].getName());
		}
	}
	
	/**
	 * Tjekker hvorvidt en spiller har vundet eller er gået bankerot.
	 */
	public Spiller[] playerUpd(Spiller[] k){
		int n=0;
		for (int i=0; i<k.length; i++){ // Antallet af spillere med negativ balance
			if (k[i].getKonto().getBalance() < 0){
				n++;
			}
		}
		
		Spiller[] f = new Spiller[n];
		int[] a = new int[n];
		int m=0;
		for (int i=0; i<k.length; i++){ //De spillere med negativ balance bliver kopieret over i et nyt array og deres balance bliver kopieret over i et int array
			if (k[i].getKonto().getBalance() < 0){ //Såfremt spillerens balance er negativ
				f[m]=k[i]; // Spilleren på plads i kopieres over på plads m
				a[m]=k[i].getKonto().getBalance(); // Spilleren på plads i's balance kopieres over på plads m
				m++;
			}
		}
		
		if(k.length==f.length){
			Arrays.sort(a); // Sorterer int array så den laveste værdi står først og den højeste værdi står sidst
			for (int i=0; i<f.length; i++){
				if(f[i].getKonto().getBalance()!=a[a.length-1]){ // Er spillerens balance forskellig fra den vindende balance?
					f = updArray(f, i); // Opdaterer spillerarrayet
				}
			}
			k=f;
			game=false;
		}
		else{
			for (int i=0; i<k.length; i++){
				if(k[i].getKonto().getBalance()<0){
				bankruptcy(k[i]); // Hvis spilleren er bankerot
				k = updArray(k, i); // Opdaterer spillerarrayet
				}
			}
			if(k.length==1){
				game=false;
			}
		}
		return k;
	}

	/**
	 * Nulstiller ownable felter på GUI'en til deres oprindelige status (Beskrivelse + pris) når en spiller er gået bankerot
	 * @param spiller Spilleren der er gået bankerot
	 */
	public void bankruptcy(Spiller spiller){
		Adapter.removeCar(spiller.getPosition(), spiller.getName()); // Fjerner spillerens bil fra spillepladen.
		int q = 0; // Positionen på spillepladen (+1)
		int o = 0;
		Ownable[] ownable = new Ownable[18];
		do{
			if (field[q] instanceof Ownable){
				ownable[o] = (Ownable) field[q];
				if (ownable[o].getOwner() == spiller){
					ownable[o].setOwner(null, q+1);
					Adapter.removeOwner(q+1);
				}
				o++;
			}
			q++;
		}
		while (q < field.length);	
	}

	/**
	 * Fjerner en spiller fra array af spillere når spilleren er bankerot
	 * @param a Spilleren der skal fjernes fra arrayet
	 * @param index Spillerens nummer/placering i arrayet
	 * @return Det nye spiller-array
	 */
	public Spiller[] updArray(Spiller[] a, int index){
		int num = a.length - (index + 1) ;
		System.arraycopy(a, index + 1, a, index, num);
		Spiller[] p = new Spiller[a.length-1];
		System.arraycopy(a, 0, p, 0, p.length);
		return p;
	}
}
